home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 176-200 / 190 / nethack / een.zoo / pcmain.c < prev    next >
C/C++ Source or Header  |  1988-07-27  |  13KB  |  666 lines

  1. /*    SCCS Id: @(#)pcmain.c   2.3     87/12/12
  2. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  3. /* main.c - (PC and AMIGA) version */
  4.  
  5. #include <stdio.h>
  6. #include <signal.h>
  7. #include "hack.h"
  8.  
  9. #ifdef AMIGA
  10. # ifdef QUEST
  11. #  define    gamename     "Amiga NetQuest"
  12. # else
  13. #  define    gamename     "Amiga NetHack"
  14. # endif
  15. #else
  16. # ifdef QUEST
  17. #  define    gamename     "PC NetQuest"
  18. # else
  19. #  define    gamename     "PC NetHack"
  20. # endif
  21. #endif
  22.  
  23. #ifdef AMIGA
  24. extern char orgdir[1];
  25. #else
  26. char orgdir[PATHLEN], *getcwd();
  27. #endif
  28.  
  29. extern struct permonst mons[CMNUM+2];
  30. extern char genocided[], fut_geno[];
  31. extern char *getlogin(), *getenv();
  32. extern char plname[PL_NSIZ], pl_character[PL_CSIZ];
  33.  
  34. int (*afternmv)(), done1(), (*occupation)();
  35.  
  36. char SAVEF[FILENAME];
  37. char *hname = gamename;
  38. char obuf[BUFSIZ];    /* BUFSIZ is defined in stdio.h */
  39. int hackpid;        /* not used anymore, but kept in for save files */
  40.  
  41. extern char *nomovemsg;
  42. extern long wailmsg;
  43.  
  44. main(argc,argv)
  45. int argc;
  46. char *argv[];
  47. {
  48.     register int fd;
  49.     register char *dir;
  50.     extern struct monst *makedog();
  51.  
  52. #ifdef AMIGA
  53.     char ch;
  54.     int abort;
  55.  
  56. /*
  57.  *  Make sure screen IO is initialized before anything happens.
  58.  */
  59.  
  60.     gettty();
  61.     startup();
  62.     hackpid = getpid();
  63. #endif
  64.  
  65. #ifdef MSDOS
  66. # ifndef AMIGA
  67.     static void moveloop(); /* a helper function for MSC optimizer */
  68.  
  69.     /* Save current directory and make sure it gets restored when
  70.      * the game is exited.
  71.      */
  72.     int (*funcp)();
  73.  
  74.     if (getcwd(orgdir, sizeof orgdir) == NULL) {
  75.         xputs("NetHack: current directory path too long\n");
  76.         _exit(1);
  77.     }
  78.     funcp = exit;    /* Kludge to get around LINT_ARGS of signal.
  79.              * This will produce a compiler warning, but that's OK.
  80.              */
  81.     signal(SIGINT, funcp);  /* restore original directory */
  82. # endif
  83. #endif
  84.  
  85. #ifdef GRAPHICS
  86.     /* Set the default values of the presentation characters */
  87.     memcpy((char *) &showsyms, (char *) &defsyms, sizeof(struct symbols));
  88. #endif
  89. #ifdef DGK
  90.     if ((dir = getenv("HACKDIR")) != (char *) NULL) {
  91.         (void) strcpy(hackdir, dir);
  92.         chdirx (dir, 1);
  93.     }
  94.     zero_finfo();
  95.     initoptions();
  96.     if (!hackdir[0])
  97.         (void) strcpy(hackdir, orgdir);
  98.     dir = hackdir;
  99. #else /* DGK */
  100.     dir = getenv("HACKDIR");
  101.     if(argc > 1 && !strncmp(argv[1], "-d", 2)) {
  102.         argc--;
  103.         argv++;
  104.         dir = argv[0]+2;
  105.         if(*dir == '=' || *dir == ':') dir++;
  106.         if(!*dir && argc > 1) {
  107.             argc--;
  108.             argv++;
  109.             dir = argv[0];
  110.         }
  111.         if(!*dir)
  112.             error("Flag -d must be followed by a directory name.");
  113.     }
  114. #endif /* DGK */
  115.  
  116.     /*
  117.      * Now we know the directory containing 'record' and
  118.      * may do a prscore().
  119.      */
  120.     if(argc > 1 && !strncmp(argv[1], "-s", 2)) {
  121.         chdirx(dir,0);
  122.         prscore(argc, argv);
  123.         exit(0);
  124.     }
  125.  
  126.     /*
  127.      * It seems he really wants to play.
  128.      * Remember tty modes, to be restored on exit.
  129.      */
  130. #ifndef AMIGA
  131.     gettty();
  132.     setbuf(stdout,obuf);
  133.     startup();
  134. #endif /* !AMIGA */
  135.     setrandom();
  136.     init_corpses(); /* initialize optional corpse names */
  137.     cls();
  138.     u.uhp = 1;    /* prevent RIP on early quits */
  139.     u.ux = FAR;    /* prevent nscr() */
  140.  
  141.     /*
  142.      * We cannot do chdir earlier, otherwise gethdate will fail.
  143.      */
  144.     chdirx(dir,1);
  145.  
  146.     /*
  147.      * Process options.
  148.      */
  149.     while(argc > 1 && argv[1][0] == '-'){
  150.         argv++;
  151.         argc--;
  152.         switch(argv[0][1]){
  153. #ifdef WIZARD
  154.         case 'D':
  155. # ifdef MSDOS
  156.             wizard = TRUE;
  157. # else /* MSDOS */
  158.             if(!strcmp(getlogin(), WIZARD))
  159.                 wizard = TRUE;
  160.             else {
  161.                 settty("Sorry, you can't operate in debug mode.\n");
  162.                 clearlocks();
  163.                 exit(0);
  164.             }
  165. # endif
  166.             break;
  167. #endif /* WIZARD */
  168. #ifdef NEWS
  169.         case 'n':
  170.             flags.nonews = TRUE;
  171.             break;
  172. #endif
  173.         case 'u':
  174.             if(argv[0][2])
  175.               (void) strncpy(plname, argv[0]+2, sizeof(plname)-1);
  176.             else if(argc > 1) {
  177.               argc--;
  178.               argv++;
  179.               (void) strncpy(plname, argv[0], sizeof(plname)-1);
  180.             } else
  181.                 printf("Player name expected after -u\n");
  182.             break;
  183. #ifdef DGK
  184.         /* Person does not want to use a ram disk
  185.          */
  186.         case 'R':
  187.             ramdisk = FALSE;
  188.             break;
  189. #endif
  190.         default:
  191.             /* allow -T for Tourist, etc. */
  192.             (void) strncpy(pl_character, argv[0]+1,
  193.                 sizeof(pl_character)-1);
  194.  
  195.             /* printf("Unknown option: %s\n", *argv); */
  196.         }
  197.     }
  198.  
  199. #ifdef DGK
  200.     set_lock_and_bones();
  201.     copybones(FROMPERM);
  202. #endif
  203. #ifdef WIZARD
  204.     if (wizard)
  205.         (void) strcpy(plname, "wizard");
  206.     else
  207. #endif
  208.     if (!*plname)
  209.         askname();
  210.     plnamesuffix();         /* strip suffix from name; calls askname() */
  211.                 /* again if suffix was whole name */
  212.                 /* accepts any suffix */
  213. #ifdef WIZARD
  214.     if(wizard) {
  215.         register char *sfoo;
  216. # ifndef DGK
  217.         /* lock is set in read_config_file */
  218.         (void) strcpy(lock,plname);
  219. # endif
  220.         if(sfoo = getenv("MAGIC"))
  221.             while(*sfoo) {
  222.                 switch(*sfoo++) {
  223.                 case 'n': (void) srand(*sfoo++);
  224.                     break;
  225.                 }
  226.             }
  227.         if(sfoo = getenv("GENOCIDED")){
  228.             if(*sfoo == '!'){
  229.                 register struct permonst *pm = mons;
  230.                 register char *gp = genocided;
  231.  
  232.                 while(pm < mons+CMNUM+2){
  233.                     if(!index(sfoo, pm->mlet))
  234.                         *gp++ = pm->mlet;
  235.                     pm++;
  236.                 }
  237.                 *gp = 0;
  238.             } else
  239.                 (void) strcpy(genocided, sfoo);
  240.             (void) strcpy(fut_geno, genocided);
  241.         }
  242.     }
  243. #endif /* WIZARD */
  244.     start_screen();
  245. #ifdef DGK
  246. # ifdef AMIGA
  247.     strncat(SAVEF, plname, 27);
  248. # else
  249.     strncat(SAVEF, plname, 8);
  250. # endif
  251.     strcat(SAVEF, ".sav");
  252.     cls();
  253.     if (saveDiskPrompt(1) && ((fd = open(SAVEF, 0)) >= 0) &&
  254.        (uptodate(fd) || !unlink(SAVEF))) {
  255. #else
  256.     (void) sprintf(SAVEF, "save/%d%s", getuid(), plname);
  257.     regularize(SAVEF+5);            /* avoid . or / in name */
  258.     if((fd = open(SAVEF,0)) >= 0 &&
  259.        (uptodate(fd) || unlink(SAVEF) == 666)) {
  260. #endif /* DGK */
  261.         (void) signal(SIGINT,done1);
  262.         pline("Restoring old save file...");
  263.         (void) fflush(stdout);
  264.         if(!dorecover(fd))
  265.             goto not_recovered;
  266.         pline("Hello %s%s, welcome to %s!",
  267.             (Badged) ? "Officer " : "", plname, hname);
  268.         flags.move = 0;
  269.     } else {
  270. not_recovered:
  271. #ifdef DGK
  272.         gameDiskPrompt();
  273. #endif
  274.         fobj = fcobj = invent = 0;
  275.         fmon = fallen_down = 0;
  276.         ftrap = 0;
  277.         fgold = 0;
  278.         flags.ident = 1;
  279.         init_objects();
  280.         u_init();
  281.  
  282.         (void) signal(SIGINT,done1);
  283.         mklev();
  284.         u.ux = xupstair;
  285.         u.uy = yupstair;
  286.         (void) inshop();
  287.         setsee();
  288.         flags.botlx = 1;
  289.         /* Fix bug with dog not being made because a monster
  290.          * was on the level 1 staircase
  291.          */
  292.         {
  293.             struct monst *mtmp;
  294.  
  295.             if (mtmp = m_at(u.ux, u.uy))
  296.                 mnexto(mtmp);
  297.         }
  298.         makedog();
  299.         { register struct monst *mtmp;
  300.           if(mtmp = m_at(u.ux, u.uy)) mnexto(mtmp);     /* riv05!a3 */
  301.         }
  302.         seemons();
  303. #ifdef NEWS
  304.         if(flags.nonews || !readnews())
  305.             /* after reading news we did docrt() already */
  306. #endif
  307.         docrt();
  308.  
  309.         /* give welcome message before pickup messages */
  310.         pline("Hello %s, welcome to %s!", plname, hname);
  311. #ifdef WIZARD
  312.         if (wizard)
  313. # ifdef STOOGES
  314. pline ("The wiz is at %d, the medusa is at %d, and the stooges are at %d",
  315.             u.wiz_level, u.medusa_level, u.stooge_level);
  316. # else
  317.             pline ("The wiz is at %d, and the medusa at %d",
  318.                u.wiz_level, u.medusa_level);
  319. # endif
  320. #endif
  321.  
  322.         pickup(1);
  323.         read_engr_at(u.ux,u.uy);
  324.         flags.move = 1;
  325.     }
  326.     flags.moonphase = phase_of_the_moon();
  327.     if(flags.moonphase == FULL_MOON) {
  328.         pline("You are lucky! Full moon tonight.");
  329.         if(!u.uluck) change_luck(1);
  330.     } else if(flags.moonphase == NEW_MOON) {
  331.         pline("Be careful! New moon tonight.");
  332.     }
  333.  
  334.     initrack();
  335.     (void) signal(SIGINT, SIG_IGN);
  336. #ifdef MSDOS
  337. # ifndef AMIGA
  338.     /* Help for Microsoft optimizer.  Otherwise main is too large -dgk*/
  339.     moveloop();
  340. }
  341.  
  342. static void
  343. moveloop()
  344. {
  345.     char ch;
  346.     int abort;
  347. # endif /* AMIGA */
  348. #endif /* MSDOS */
  349.     for(;;) {
  350.         if(flags.move) {        /* actual time passed */
  351.  
  352.             settrack();
  353.  
  354.             if(moves%2 == 0 ||
  355.               (!(Fast & ~INTRINSIC) && (!Fast || rn2(3)))) {
  356.                 extern struct monst *makemon();
  357.                 movemon();
  358. #ifdef HARD
  359.                 if(!rn2(u.udemigod?25:(dlevel>30)?50:70))
  360. #else
  361.                 if(!rn2(70))
  362. #endif
  363.                     (void) makemon((struct permonst *)0, 0, 0);
  364.             }
  365.             if(Glib) glibr();
  366.             timeout();
  367.             ++moves;
  368. #ifdef PRAYERS
  369.             if (u.ublesscnt)  u.ublesscnt--;
  370. #endif
  371. #ifndef DGK
  372.             if(flags.time) flags.botl = 1;
  373. #endif
  374. #ifdef KAA
  375.             if(u.mtimedone)
  376.                 if(u.mh < 1) rehumanize();
  377.             else
  378. #endif
  379.                 if(u.uhp < 1) {
  380.                 pline("You die...");
  381.                 done("died");
  382.                 }
  383.             if(u.uhp*10 < u.uhpmax && moves-wailmsg > 50){
  384.                 wailmsg = moves;
  385. #ifdef KAA
  386.                 if(index("WEV", pl_character[0])) {
  387.                     if (u.uhp == 1)
  388.                        pline("%s is about to die.", pl_character);
  389.                     else
  390.                        pline("%s, your life force is running out.",
  391.                         pl_character);
  392.                 } else {
  393. #endif
  394.                 if(u.uhp == 1)
  395.                 pline("You hear the wailing of the Banshee...");
  396.                 else
  397.                 pline("You hear the howling of the CwnAnnwn...");
  398. #ifdef KAA
  399.                 }
  400. #endif
  401.             }
  402. #ifdef KAA
  403.             if (u.mtimedone) {
  404.                 if (u.mh < u.mhmax) {
  405.                 if (Regeneration || !(moves%20)) {
  406.                     flags.botl = 1;
  407.                     u.mh++;
  408.                 }
  409.                 }
  410.             }
  411. #endif
  412.             if(u.uhp < u.uhpmax) {
  413.                 if(u.ulevel > 9) {
  414.                     if(HRegeneration || !(moves%3)) {
  415.                         flags.botl = 1;
  416.                         u.uhp += rnd((int) u.ulevel-9);
  417.                         if(u.uhp > u.uhpmax)
  418.                         u.uhp = u.uhpmax;
  419.                     }
  420.                 } else if(HRegeneration ||
  421.                     (!(moves%(22-u.ulevel*2)))) {
  422.                     flags.botl = 1;
  423.                     u.uhp++;
  424.                 }
  425.             }
  426. #ifdef SPELLS
  427.             if ((u.uen<u.uenmax) && (!(moves%(21-u.ulevel/2)))) {
  428.                 u.uen += rn2(u.ulevel/4 + 1) + 1;
  429.                 if (u.uen > u.uenmax)  u.uen = u.uenmax;
  430.                 flags.botl = 1;
  431.             }
  432. #endif
  433.             if(Teleportation && !rn2(85)) tele();
  434. /* #if defined(KAA) && defined(BVH) */
  435. #ifdef KAA
  436. # ifdef BVH
  437.             if(Polymorph && !rn2(100)) polyself();
  438. # endif
  439. #endif
  440.             if(Searching && multi >= 0) (void) dosearch();
  441.             gethungry();
  442.             invault();
  443.             amulet();
  444. #ifdef HARD
  445.             if (!rn2(50+(u.ulevel*3))) u_wipe_engr(rnd(3));
  446.             if (u.udemigod) {
  447.  
  448.                 u.udg_cnt--;
  449.                 if(u.udg_cnt <= 0) {
  450.  
  451.                     intervene();
  452.                     u.udg_cnt = rn1(200, 50);
  453.                 }
  454.             }
  455. #endif
  456.         }
  457.         if(multi < 0) {
  458.             if(!++multi){
  459.                 pline(nomovemsg ? nomovemsg :
  460.                     "You can move again.");
  461.                 nomovemsg = 0;
  462.                 if(afternmv) (*afternmv)();
  463.                 afternmv = 0;
  464.             }
  465.         }
  466.  
  467.         find_ac();
  468. #ifndef QUEST
  469.         if(!flags.mv || Blind)
  470. #endif
  471.         {
  472.             seeobjs();
  473.             seemons();
  474.             nscr();
  475.         }
  476. #ifdef DGK
  477.         if(flags.time) flags.botl = 1;
  478. #endif
  479.         if(flags.botl || flags.botlx) bot();
  480.  
  481.         flags.move = 1;
  482.  
  483.         if(multi >= 0 && occupation) {
  484. #ifdef DGK
  485.             abort = 0;
  486.             if (kbhit()) {
  487.                 if ((ch = getchar()) == ABORT)
  488.                     abort++;
  489. # ifdef REDO
  490.                 else
  491.                     pushch(ch);
  492. # endif
  493.             }
  494.             if (abort || monster_nearby())
  495.                 stop_occupation();
  496.             else if ((*occupation)() == 0)
  497.                 occupation = 0;
  498.             if (!(++occtime % 7))
  499.                 (void) fflush(stdout);
  500. #else
  501.             if (monster_nearby())
  502.                 stop_occupation();
  503.             else if ((*occupation)() == 0)
  504.                 occupation = 0;
  505. #endif
  506.             continue;
  507.         }
  508.  
  509.         if(multi > 0) {
  510. #ifdef QUEST
  511.             if(flags.run >= 4) finddir();
  512. #endif
  513.             lookaround();
  514.             if(!multi) {    /* lookaround may clear multi */
  515.                 flags.move = 0;
  516.                 continue;
  517.             }
  518.             if(flags.mv) {
  519.                 if(multi < COLNO && !--multi)
  520.                     flags.mv = flags.run = 0;
  521.                 domove();
  522.             } else {
  523.                 --multi;
  524.                 rhack(save_cm);
  525.             }
  526.         } else if(multi == 0) {
  527. #ifdef MAIL
  528.             ckmailstatus();
  529. #endif
  530.             rhack((char *) 0);
  531.         }
  532.         if(multi && multi%7 == 0)
  533.             (void) fflush(stdout);
  534.     }
  535. }
  536.  
  537. #ifndef DGK
  538. /* This function is unnecessary and incompatible with the #define
  539.  * of glo(x) in config.h -dgk
  540.  */
  541. glo(foo)
  542. register foo;
  543. {
  544.     /* construct the string  xlock.n  */
  545.     register char *tf;
  546.  
  547.     tf = lock;
  548.     while(*tf && *tf != '.') tf++;
  549.     (void) sprintf(tf, ".%d", foo);
  550. }
  551. #endif
  552.  
  553. /*
  554.  * plname is filled either by an option (-u Player  or  -uPlayer) or
  555.  * explicitly (-D implies wizard) or by askname.
  556.  * It may still contain a suffix denoting pl_character.
  557.  */
  558. askname(){
  559. register int c,ct;
  560.     printf("\nWho are you? ");
  561.     (void) fflush(stdout);
  562.     ct = 0;
  563.     while((c = getchar()) != '\n'){
  564.         if(c == EOF) error("End of input\n");
  565.         /* some people get confused when their erase char is not ^H */
  566.         if(c == '\b') {
  567.             if(ct) {
  568.                 ct--;
  569. #ifdef MSDOS
  570.                 msmsg("\b \b");
  571. #endif
  572.             }
  573.             continue;
  574.         }
  575.         if(c != '-')
  576.         if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_';
  577. #ifdef MSDOS
  578.         msmsg("%c", c);
  579. #endif
  580.         if(ct < sizeof(plname)-1) plname[ct++] = c;
  581.     }
  582.     plname[ct] = 0;
  583.     if(ct == 0) askname();
  584. }
  585.  
  586. /*VARARGS1*/
  587. impossible(s,x1,x2)
  588. register char *s;
  589. {
  590.     pline(s,x1,x2);
  591.     pline("Program in disorder - perhaps you'd better Quit.");
  592. }
  593.  
  594. #ifdef CHDIR
  595. chdirx(dir, wr)
  596. char *dir;
  597. boolean wr;
  598. {
  599.  
  600.     if(dir && chdir(dir) < 0) {
  601.         error("Cannot chdir to %s.", dir);
  602.     }
  603.  
  604. #ifdef DGK
  605. # ifndef AMIGA
  606.     /* Change the default drive as well.
  607.      */
  608.     chdrive(dir);
  609. # endif
  610. #endif
  611.  
  612.     /* warn the player if he cannot write the record file */
  613.     /* perhaps we should also test whether . is writable */
  614.     /* unfortunately the access systemcall is worthless */
  615.     if(wr) {
  616.         register fd;
  617.  
  618.         if(dir == NULL)
  619. #ifdef AMIGA
  620.         dir = "";
  621. #else
  622.         dir = ".";
  623. #endif
  624.         if((fd = open(RECORD, 2)) < 0) {
  625. #ifdef DGK
  626.         char tmp[PATHLEN];
  627.  
  628.         strcpy(tmp, dir);
  629.         append_slash(tmp);
  630.         msmsg("Warning: cannot write %s%s\n", tmp, RECORD);
  631.         getreturn("to continue");
  632. #else
  633.         printf("Warning: cannot write %s/%s", dir, RECORD);
  634.         getret();
  635. #endif
  636.         } else
  637.         (void) close(fd);
  638.     }
  639. }
  640. #endif /* CHDIR /**/
  641.  
  642. stop_occupation()
  643. {
  644.     extern void pushch();
  645.  
  646.     if(occupation) {
  647.         pline("You stop %s.", occtxt);
  648.         occupation = 0;
  649. #ifdef REDO
  650.         multi = 0;
  651.         pushch(0);
  652. #endif
  653.     }
  654. }
  655.  
  656. #ifdef DGK
  657. struct finfo    zfinfo = ZFINFO;
  658.  
  659. zero_finfo() {  /* zero "fileinfo" array to prevent crashes on level change */
  660.     int i;
  661.  
  662.     for (i = 0 ; i <= MAXLEVEL; i++)
  663.         fileinfo[i] = zfinfo;
  664. }
  665. #endif
  666.